/*
 * Niiuzu
 * Copyright (C) 2011  Thierry Nowak
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.niiuzu.client.screen.authentification.signup;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.inject.Inject;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.LazyPresenter;
import com.niiuzu.client.eventbus.AuthentificationEventBus;
import com.niiuzu.client.i18n.AuthentificationMessages;
import com.niiuzu.client.util.ClientContextFactory;
import com.niiuzu.client.util.LoadingTicket;
import com.niiuzu.client.util.SessionClient;
import com.niiuzu.client.util.callback.AbstractCallback;
import com.niiuzu.client.util.regexp.RegExp;
import com.niiuzu.client.util.regexp.RegExpGwt;
import com.niiuzu.shared.model.UserLogInResult;
import com.niiuzu.shared.rpc.UserServiceAsync;

/**
 * Presenter de la création de compte utilisateur.
 */
@Presenter(view = SignUpViewImpl.class)
public class SignUpPresenter extends
		LazyPresenter<SignUpView, AuthentificationEventBus> {

	private static final String REGEXP_MAIL = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,3}$";

	@Inject
	private UserServiceAsync userService;

	@Inject
	private AuthentificationMessages authentificationMessages;

	private RegExp regExp = new RegExpGwt();

	private ClickHandler closeClickHandler;
	private ClickHandler validateClickHandler;

	@Override
	public void bindView() {
		super.bindView();

		closeClickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				view.hidePopup();
			}
		};
		view.getCloseButtonHasClickHandlers()
				.addClickHandler(closeClickHandler);
		view.getCancelHasClickHandlers().addClickHandler(closeClickHandler);

		validateClickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				launchUserSignUp();
			}
		};
		view.getValidationHasClickHandlers().addClickHandler(
				validateClickHandler);
	}

	/**
	 * Affichage du formulaire de création de compte.
	 * 
	 * @see AuthentificationEventBus#signUpFormWanted()
	 */
	public void onSignUpFormWanted() {
		view.getMailHasValue().setValue("");
		view.getPasswordHasValue().setValue("");
		view.getPasswordConfirmationHasValue().setValue("");

		view.showPopup();
		view.focusMailField();
	}

	/**
	 * Lancement de la création de l'utilisateur.
	 */
	void launchUserSignUp() {
		String mail = view.getMailHasValue().getValue();
		String password = view.getPasswordHasValue().getValue();
		String passwordConfirm = view.getPasswordConfirmationHasValue()
				.getValue();

		// Mail manquant
		if (mail.isEmpty()) {
			displayError(authentificationMessages.errorMissingMailValue());
		}
		// Mail au mauvais format
		else if (!regExp.test(REGEXP_MAIL, mail)) {
			displayError(authentificationMessages.errorWrongMailFormat());
		}
		// Mot de passe manquant
		else if (password.isEmpty()) {
			displayError(authentificationMessages.errorMissingPasswordValue());
		}
		// Confirmation du mot de passe manquant
		else if (passwordConfirm.isEmpty()) {
			displayError(authentificationMessages
					.errorMissingPasswordConfirmationValue());
		}
		// Les mots de passe ne correspondent pas
		else if (!password.equals(passwordConfirm)) {
			displayError(authentificationMessages.errorInvalidPasswords());
		}
		// Valeurs
		else {

			final LoadingTicket ticket = LoadingTicket.Factory.createTicket(
					getClass(), authentificationMessages.validationSignUp());

			eventBus.loadingStarted(ticket);

			userService.createUserAccount(mail, password, ClientContextFactory
					.get(), new AbstractCallback<UserLogInResult>(eventBus,
					ticket) {
				@Override
				public void onSuccess(UserLogInResult result) {
					receiveSignUpResponse(result, ticket);
				}
			});
		}
	}

	/**
	 * Affiche le message d'erreur et réinitialise les champs critiques du
	 * formulaire.
	 */
	private void displayError(String error) {
		eventBus.businessErrorOccurred(error);
		view.getPasswordHasValue().setValue("");
		view.getPasswordConfirmationHasValue().setValue("");
	}

	/**
	 * Réception de la réponse suite à la création d'un compte utilisateur.
	 * 
	 * @param result
	 *            réponse provenant du serveur.
	 * @param ticket
	 *            ticket de chargement correspondant à la création du compte.
	 */
	void receiveSignUpResponse(UserLogInResult result, LoadingTicket ticket) {
		if (result == null || result.getUser() == null) {
			eventBus.loadingFinished(ticket);
			displayError(authentificationMessages.errorWrongServerResponse());
		} else {

			SessionClient sessionClient = getSessionClient();
			sessionClient.setUser(result.getUser());

			view.hidePopup();

			eventBus.userLoggedIn(ticket);
		}
	}

	/**
	 * Comportement affecté au clic sur le bouton de fermeture.
	 */
	ClickHandler getCloseClickHandler() {
		return closeClickHandler;
	}

	/**
	 * Comportement affecté à la validation du formulaire.
	 */
	ClickHandler getValidateClickHandler() {
		return validateClickHandler;
	}

	/**
	 * Retourne une instance de {@link SessionClient}.
	 */
	private SessionClient getSessionClient() {
		if (mockedSessionClient != null) {
			return mockedSessionClient;
		}
		return SessionClient.getInstance();
	}

	/* ********************************************************************** */
	/* ********************************************************************** */
	/* ********************************************************************** */

	private SessionClient mockedSessionClient;

	/**
	 * JUnit - Définit un mock pour {@link UserServiceAsync}.
	 */
	void setMockedUserService(UserServiceAsync mockedUserService) {
		this.userService = mockedUserService;
	}

	/**
	 * JUnit - Définit un mock pour {@link SessionClient}.
	 */
	void setMockedSessionClient(SessionClient mockedSessionClient) {
		this.mockedSessionClient = mockedSessionClient;
	}

	/**
	 * JUnit - Définit un mock pour {@link AuthentificationMessages}.
	 */
	void setMockedAuthentificationMessages(
			AuthentificationMessages mockedAuthentificationMessages) {
		this.authentificationMessages = mockedAuthentificationMessages;
	}

	/**
	 * JUnit - Définit un mock pour {@link RegExp}.
	 */
	void setMockedRegExp(RegExp regExp) {
		this.regExp = regExp;
	}
}
